package p.ithorns.tools.translator.sdk.handler;

import com.google.auto.service.AutoService;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;
import p.ithorns.tools.translator.annotation.Translator;
import p.ithorns.tools.translator.annotation.field.ExpField;
import p.ithorns.tools.translator.sdk.exception.DictFieldException;

import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * SpElTranslator
 *
 * 通过Spring SpEL表达式解析服务及方法实现字典转换
 * 适用于需要灵活定义字典接口的场景
 *
 * @author Ht.L
 * @date 2025-02-05 22:28
 * @since 1.0.0
 */
@AutoService(Translator.class)
public class SpElTranslator<T extends Serializable> implements Translator<T, ExpField> {

//    private final String GET_ONE = ".getDict(#key)";
//
//    private final String GET_MAP = ".getDictMap(#keys)";

    private final StandardEvaluationContext ctx;

    private final ExpressionParser parser;


    public SpElTranslator(ApplicationContext appCtx) {
        // 创建数据上下文
        this.ctx = new StandardEvaluationContext();
        // 创建表达式解析器
        this.parser = new SpelExpressionParser();

        AutowireCapableBeanFactory beanFactory = appCtx.getAutowireCapableBeanFactory();
        ctx.setBeanResolver(new BeanFactoryResolver(beanFactory));
    }


    @Override
    public String translate(ExpField annotation, T key) {
        String el = annotation.expr1();
        if (!StringUtils.hasText(el)) {
            throw new DictFieldException("@ExpField: expr1 is not specified");
        }
        ctx.setVariable("key", key);
        return getDictFunc().apply(el);
    }

    @Override
    public Map<T, Object> translate(ExpField annotation, Set<T> keys) {
        String el = annotation.expr2();
        if (!StringUtils.hasText(el)) {
            throw new DictFieldException("@ExpField: expr2 is not specified");
        }
        ctx.setVariable("keys", keys);
        return getDictMapFunc().apply(el);
    }

    private Function<String, String> getDictFunc() {
        return el -> {
            Expression expression = parser.parseExpression(el);
            return expression.getValue(ctx, String.class);
        };
    }

    @SuppressWarnings("unchecked")
    private Function<String, Map<T, Object>> getDictMapFunc() {
        return el -> {
            // TODO 使用缓存机制存储已解析的表达式，避免重复解析, 降低开销
            Expression expression = parser.parseExpression(el);
            // 这里需要反射调用bean方法
            // @see org.springframework.expression.spel.ast.MethodReference.getValueInternal(org.springframework.expression.EvaluationContext, java.lang.Object, org.springframework.core.convert.TypeDescriptor, java.lang.Object[])
            return expression.getValue(ctx, Object.class, Map.class);
        };
    }

}